package se.webbzon.boltzmann.minigame.sandbox;

import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import se.webbzon.boltzmann.geometries.Geometries;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldcamera.WorldCameraPane;
import se.webbzon.oschi01.worldobject.WorldObject;

public class SandBoxArrow extends DefaultSandBoxItem {
	
	// The 2-dimensional depth of the rain
	private static final int depth = 125;
	
	// The anchors of this sand box arrow
	private final List<SandBoxAnchor> anchors;
	
	// The object pool used for drawing
	private final AffineTransform t;
	private final Point2D p1, p2;
	private final Rectangle2D rect;
	private final Line2D line;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public SandBoxArrow(SandBoxAnchor tail, SandBoxAnchor head) {
		setInstance(new Instance());
		anchors = new ArrayList<SandBoxAnchor>();
		anchors.add(tail);
		anchors.add(head);
		t = new AffineTransform();
		p1 = new Point2D.Double();
		p2 = new Point2D.Double();
		rect = new Rectangle2D.Double();
		line = new Line2D.Double();
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Adds a new anchor to the sand box arrow. **/
	public void addAnchor(SandBoxAnchor anchor) {
		anchors.add(anchors.size()-1, anchor);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	public final class Instance extends SandBoxObject {

		public Instance() {
			super(WorldObject.onPostDraw, depth);
		}

		@Override public void onAttach(SandBox box) {};

		@Override public void onDetach(SandBox box) {};

		@Override public SandBoxIcon createIcon() {
			return null;
		}

		@Override public void onPostDraw(WorldArea world, WorldCameraPane hud) {
			hud.setColor(Color.black);
			Iterator<SandBoxAnchor> it = anchors.iterator();
			SandBoxAnchor from = it.next();
			boolean first = true;
			while (true) {
				SandBoxAnchor to = it.next();
				int fx = (int) from.getX(), fy = (int) from.getY(),
					tx = (int) to.getX(), ty = (int) to.getY();
				if (first) {
					int w = (int) from.getWidth(), 
						h = (int) from.getHeight();
					p1.setLocation(fx, fy);
					p2.setLocation(tx, ty);
					rect.setRect(fx - w/2, fy - h/2, w, h);
					atEdge(p1,p2,rect,line);
					fx = (int) line.getX1();
					fy = (int) line.getY1();
					first = false;
				}
				if (it.hasNext()) {
					hud.drawLine(fx,fy,tx,ty);
					from = to;
				} else {
					int w = (int) to.getWidth(), 
						h = (int) to.getHeight();
					p1.setLocation(tx, ty);
					p2.setLocation(fx, fy);
					rect.setRect(tx - w/2, ty - h/2, w, h);
					atEdge(p1,p2,rect,line);
					tx = (int) line.getX1();
					ty = (int) line.getY1();
					hud.drawLine(fx,fy,tx,ty);
					t.setToTranslation(tx, ty);
					t.rotate(Math.atan2(ty-fy, tx-fx) + Math.PI/2);
					hud.setTransform(t);
					hud.fillPolygon(0, 0, Geometries.arrow());
					hud.resetTransform();
					break;
				}
			}
		}	
		
	}
	
	
	/*============================================================
	Private Methods
	============================================================*/
	
	private static final void atEdge(Point2D from, Point2D to, Rectangle2D box, Line2D line) {
		double fx = from.getX();
		double tx = to.getX();
		double fy = from.getY();
		double ty = to.getY();
		if (fx > tx) {
			if (fy > ty) {
				// Invert both axis
				to.setLocation(-tx, -ty);
				from.setLocation(-fx, -fy);
				box.setRect(-box.getMaxX(), -box.getMaxY(), box.getWidth(), box.getHeight());
				atEdge(from,to,box,line);
				line.setLine(-line.getX1(), -line.getY1(), -line.getX2(), -line.getY2());
			} else {
				// Invert x-axis
				to.setLocation(-tx, ty);
				from.setLocation(-fx, fy);
				box.setRect(-box.getMaxX(),box.getY(), box.getWidth(), box.getHeight());
				atEdge(from,to,box,line);
				line.setLine(-line.getX1(), line.getY1(), -line.getX2(), line.getY2());
			}
		} else if (fy > ty) { 
			// Invert y-axis
			to.setLocation(tx, -ty);
			from.setLocation(fx, -fy); 
			box.setRect(box.getX(), -box.getMaxY(), box.getWidth(), box.getHeight());
			atEdge(from,to,box,line);
			line.setLine(line.getX1(), -line.getY1(), line.getX2(), -line.getY2());
		} else {
			double w = box.getMaxX() - fx;
			double h = box.getMaxY() - fy;
			double angle = Math.atan2(ty-fy,tx-fx);
			double boxAngle = Math.atan2(h,w);
			double sx, sy;
			if (angle <= boxAngle) {
				sx = w;
				sy = sx * Math.tan(angle);
			} else {
				sy = h;
				sx = sy / Math.tan(angle);
			}
			line.setLine(fx + sx, fy + sy,tx,ty);
		} 
	}
	

}
